package com.gitee.kamismile.stoneComEx.common.exception.server;

import com.gitee.kamismile.stoneComEx.common.component.base.LoggerInfoVO;
import com.gitee.kamismile.stoneComEx.util.IpUtil;
import com.gitee.kamismile.stoneComEx.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import com.gitee.kamismile.stone.commmon.base.ResultVO;
import com.gitee.kamismile.stone.commmon.exception.BusinessException;
import com.gitee.kamismile.stone.commmon.util.JsonUtil;
import com.gitee.kamismile.stone.commmon.util.ValueUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.WebProperties.Resources;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.annotation.Order;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.i18n.LocaleContextResolver;

import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;

@Component
@Order(-2)
public class OtherFluxErrorController extends DefaultErrorWebExceptionHandler {

    @Autowired
    private ReloadableResourceBundleMessageSource messageSource;


    protected final Logger logger = LoggerFactory.getLogger("bLog");

    public OtherFluxErrorController(ErrorAttributes errorAttributes, WebProperties webProperties,
                                    ServerProperties serverProperties, ApplicationContext applicationContext,
                                    ServerCodecConfigurer serverCodecConfigurer,
                                    ObjectProvider<List<ViewResolver>> viewResolversProvider) {
        super(errorAttributes, webProperties.getResources(), serverProperties.getError(), applicationContext);
        this.setViewResolvers(viewResolversProvider.getIfAvailable(Collections::emptyList));
        this.setMessageWriters(serverCodecConfigurer.getWriters());
        this.setMessageReaders(serverCodecConfigurer.getReaders());
    }


//    /**
//     * 获取异常属性
//     */
//    @Override
//    protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
//        return getErrorMap(request);
//    }

    private Map<String, Object> getErrorMap(ServerRequest request) {
        Locale locale = LocaleContextHolder.getLocale();
        Throwable ex = super.getError(request);
        int code = -1;
        String defMessage = messageSource.getMessage(String.valueOf(code), null, locale);
        ResultVO errorMsg = new ResultVO();
        if (ex instanceof BusinessException) {
            code = ((BusinessException) ex).getCode();
            defMessage = messageSource.getMessage(String.valueOf(code), ((BusinessException) ex).getArgs(), locale);
            if(defMessage.equals(String.valueOf(code))){
                defMessage = ValueUtils.isStringNull(((BusinessException) ex).getMessage());
            }

            errorMsg.setData(((BusinessException) ex).getData());
        } else if (ex instanceof ResponseStatusException) {
            String message = ((ResponseStatusException) ex).getReason();
            defMessage=ValueUtils.isStringNull(message,defMessage);
            code=((ResponseStatusException) ex).getStatusCode().value();
        } else if (ex instanceof DuplicateKeyException) {
            defMessage = messageSource.getMessage("10001", null, locale);
        }
        errorMsg.setCode(String.valueOf(code));
        errorMsg.setMessage(defMessage);

        HttpStatus httpStatus = HttpStatus.resolve(code);
        httpStatus= Objects.isNull(httpStatus)?HttpStatus.OK:httpStatus;

        Map<String, Object> result = new HashMap<>();
        result.put("status", httpStatus.value());
        result.put("code", code);
        result.put("data", errorMsg.getData());
        result.put("message", defMessage);
        result.put("errors", Arrays.asList(errorMsg));


//        LoggerInfoVO loggerInfoVO = new LoggerInfoVO();
//        loggerInfoVO.setMethodName(request.methodName());
//        loggerInfoVO.setHeaders(JsonUtil.toJson(request.exchange().getRequest().getHeaders().toSingleValueMap()));
//        loggerInfoVO.setUrl(ValueUtils.isStringNull(request.uri().toString()));
//        loggerInfoVO.setIp(IpUtil.getIpByServerRequest(request));
//        loggerInfoVO.setMessage(message);
//        loggerInfoVO.setEx(ExceptionUtils.getStackTrace(ex));
//
//        logger.error("{}",JsonUtil.toJson(loggerInfoVO));
        logger.error(MessageFormat.format("调用接口:{0} {1} {2} IP:{3} 异常信息:{4}{5}",
                request.methodName(),
                request.exchange().getRequest().getHeaders().toSingleValueMap(),
                ValueUtils.isStringNull(request.uri().toString()), IpUtil.getIpByServerRequest(request), defMessage, ExceptionUtils.getStackTrace(ex)));
        return result;
    }

    @Override
    protected Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        return getErrorMap(request);
    }
//    @Override
//    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
//        return super.getRoutingFunction(errorAttributes)
//                .route(aPredicate, aHandler)
//                .andRoute(anotherPredicate, anotherHandler);
//    }

    @Override
    protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
        return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
    }


//    protected void logError(ServerRequest request, HttpStatus errorStatus) {
//        Throwable ex = super.getError(request);
//        MultiValueMap<String, String> params = request.queryParams();
//        Map<String, List<String>> info = new HashMap<>();
//        info.putAll(params);
//        Optional<MediaType> contentType = request.headers().contentType();
//        contentType.ifPresent(v -> {
//            if (!MediaType.MULTIPART_FORM_DATA.isCompatibleWith(v)) {
//                AtomicReference<Map> ref = new AtomicReference<>();
//
//                request.bodyToMono(Map.class).doOnSuccessOrError((map, throwable) -> {
//                    ref.set(map);
////                    logger.error(MessageFormat.format("调用接口:{0} {1} 调用参数:{2}  IP:{3} 异常信息:{4}",
////                            request.methodName(),
////                            ValueUtils.isStringNull(request.uri().toString()),
////                            JsonUtil.toJson(info), IpUtil.getIpByServerRequest(request), ex));
//                }).subscribe();
//                info.put("requestBody", Arrays.asList(JsonUtil.toJson(ref.get())));
////                request.bodyToMono(Map.class).subscribe(s -> {
////                    info.put("requestBody", Arrays.asList(JsonUtil.toJson(s)));
////                    logger.error(MessageFormat.format("调用接口:{0} {1} 调用参数:{2}  IP:{3} 异常信息:{4}",
////                            request.methodName(),
////                            ValueUtils.isStringNull(request.uri().toString()),
////                            JsonUtil.toJson(info), IpUtil.getIpByServerRequest(request), ex));
////                });
////                info.put("requestBody", Arrays.asList(JsonUtil.toJson(request.bodyToMono(Map.class))));
//            }
//        });
//
////        LoggerInfoVO loggerInfoVO = new LoggerInfoVO();
////        loggerInfoVO.setMethodName(request.methodName());
////        loggerInfoVO.setHeaders(JsonUtil.toJson(request.exchange().getRequest().getHeaders().toSingleValueMap()));
////        loggerInfoVO.setUrl(ValueUtils.isStringNull(request.uri().toString()));
////        loggerInfoVO.setIp(IpUtil.getIpByServerRequest(request));
////        loggerInfoVO.setRequestBody(JsonUtil.toJson(info));
////        loggerInfoVO.setEx(ExceptionUtils.getStackTrace(ex));
////
////        logger.error("{}",JsonUtil.toJson(loggerInfoVO));
//
//        logger.error(MessageFormat.format("调用接口:{0} {1} {2}调用参数:{3}  IP:{4} 异常信息:{5}",
//                request.methodName(),
//                request.exchange().getRequest().getHeaders().toSingleValueMap(),
//                ValueUtils.isStringNull(request.uri().toString()),
//                JsonUtil.toJson(info), IpUtil.getIpByServerRequest(request), ExceptionUtils.getStackTrace(ex)));
////        super.logError(request, errorStatus);
//    }
}
